import re

from django.contrib.auth.backends import ModelBackend

from apps.users.models import User

from itsdangerous import TimedJSONWebSignatureSerializer as Serializer
from itsdangerous import BadSignature, SignatureExpired

from meiduomall import settings

"""
封装/抽取的思想
    为什么要封装/抽取
    1、减低代码的耦合度      （高内聚、低耦合）
    2、提高代码的重用性
    
    抽取/封装的步骤
        1、定义一个函数（方法），把要抽取的代码复制过来
        2、哪里有问题，改哪里，没有的变量以参数形式定义
        3、验证抽取方法
"""


def get_user_by_username(username):
    # 1、username 可能是手机号，也可能是用户名
    # 通过对username进行正则来区分是手机号还是用户名
    try:
        if re.match(r'1[3-9]\d{9}', username):
            # username 是手机号
            user = User.objects.get(mobile=username)
        else:
            # username 是用户名
            user = User.objects.get(username=username)

    except User.DoesNotExist:
        return None

    return user


class UsernameMobileModelBackend(ModelBackend):
    def authenticate(self, request, username=None, password=None, **kwargs):
        # # 1、username 可能是手机号，也可能是用户名
        # # 通过对username进行正则来区分是手机号还是用户名
        user = get_user_by_username(username)

        # 2、判断用户的密码是否正确
        if user is not None and user.check_password(password):
            return user


def active_email_url(email, user_id):
    # 加密数据
    # 1、创建实例
    s = Serializer(secret_key=settings.SECRET_KEY, expires_in=3600)
    # 2、组织数据
    data = {
        'email': email,
        'id': user_id,
    }
    # 加密
    token = s.dumps(data)
    # 返回激活url
    return 'http://www.meiduo.site:8000/email_active?token=%s' % token.decode()


def check_email_active_token(token):
    # 解密数据
    # 创建实例
    s = Serializer(secret_key=settings.SECRET_KEY, expires_in=3600)
    # 解密数据
    try:
        result = s.loads(token)
    # except SignatureExpired:
    #     pass
    # 验证URL超时或者加密的token被篡改
    except BadSignature:
        return None
    # 获取数据
    email = result.get('email')
    id = result.get('id')
    # 返回数据
    # 我们就直接在这里查询数据库了，然后再返回
    try:
        user = User.objects.get(id=id, email=email)
    except User.DoesNotExist:
        return None
    return user
